package com.lmx.persistence.service;

import java.text.ParseException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.Query;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.lmx.common.constants.CommonConstants;
import com.lmx.common.util.CommonUtil;
import com.lmx.persistence.flow.enums.EmployeeLeaveEnum;
import com.lmx.persistence.service.common.BaseCrudServiceImpl;
import com.lmx.repoDomain.exception.BusinessException;
import com.lmx.repoDomain.tmodel.Employee;
import com.lmx.repoDomain.tmodel.EmployeeLeaveFlow;

/**
 * 员工请假service实现
 *
 * @author ytche
 * @date 2017年7月12日
 *
 */
@Service(value = "employeeLeaveFlowService")
public class EmployeeLeaveFlowServiceImpl extends BaseCrudServiceImpl<EmployeeLeaveFlow> implements
		EmployeeLeaveFlowService {
	private Log logger = LogFactory.getLog(this.getClass());
	@Autowired
	private EmployeeService employeeService;

	@Override
	public EmployeeLeaveFlow create(EmployeeLeaveFlow employeeLeaveFlow) {
		employeeLeaveFlow.setApplyTime((int) (new Date().getTime() / 1000));
		if (employeeLeaveFlow.getFlowStatus() == null) {
			employeeLeaveFlow.setFlowStatus(EmployeeLeaveEnum.APPLY.getValue());
		}
		return super.create(employeeLeaveFlow);
	}

	@Override
	public EmployeeLeaveFlow update(EmployeeLeaveFlow employeeLeaveFlow) {
		EmployeeLeaveFlow oldData = super.findOne(employeeLeaveFlow.getId());
		boolean updateInfo = oldData.getFlowStatus().equals(employeeLeaveFlow.getFlowStatus());
		boolean flowPassed = (oldData.getFlowStatus().equals(EmployeeLeaveEnum.PASS_YES.getValue()) || oldData
				.getFlowStatus().equals(EmployeeLeaveEnum.END.getValue()));
		if (updateInfo && flowPassed) {
			throw new BusinessException("",
					CommonConstants.EMPLOYEE_LEAVE_ERROR.FLOW_PASSED.lable(), "");
		}
		return super.update(employeeLeaveFlow);
	}

	@Override
	public List<EmployeeLeaveFlow> recordLeaveStatus(Map<String, String> filter) {
		if (!(filter.containsKey("startTime") || filter.containsKey("endTime"))) {
			return null;
		}
		Integer startTime = StringUtils.isBlank(filter.get("startTime")) ? 0 : new Integer(
				filter.get("startTime"));
		Integer endTime = StringUtils.isBlank(filter.get("endTime")) ? 0 : new Integer(
				filter.get("endTime"));
		List<EmployeeLeaveFlow> flows = this.findCusomerInLeave(filter);
		if (flows == null || flows.size() < 1) {
			return flows;
		}
		// 计算请假日期
		for (EmployeeLeaveFlow employeeLeaveFlow : flows) {
			// startTime取较大值,endTime取较小值
			Set<Integer> leaveDays = Sets.newHashSet();
			Integer recordStartTime = startTime > employeeLeaveFlow.getExpectStartTime() ? startTime
					: employeeLeaveFlow.getExpectStartTime();
			Integer recordEndTime = employeeLeaveFlow.getRealEndTime() == null
					|| employeeLeaveFlow.getRealEndTime() > endTime ? endTime : employeeLeaveFlow
					.getRealEndTime();
			recordStartTime = CommonUtil.getDayBegin(recordStartTime);
			recordEndTime = CommonUtil.getDayBegin(recordEndTime) + 3600 * 24;
			for (; recordStartTime < recordEndTime; recordStartTime = recordStartTime + 3600 * 24) {
				Integer day = new DateTime(recordStartTime.longValue() * 1000).getDayOfWeek();
				// jodaTime的周日为7 转换为0
				leaveDays.add(day.equals(7) ? 0 : day);
			}
			employeeLeaveFlow.setLeaveDay(leaveDays);
		}
		// 处理重复数据
		Map<Long, EmployeeLeaveFlow> flowMap = Maps.newHashMap();
		for (EmployeeLeaveFlow employeeLeaveFlow : flows) {
			Long employeeId = employeeLeaveFlow.getApplicant().getId();
			if (flowMap.containsKey(employeeId)) {
				EmployeeLeaveFlow flow = flowMap.get(employeeId);
				flow.getLeaveDay().addAll(employeeLeaveFlow.getLeaveDay());
			} else {
				flowMap.put(employeeId, employeeLeaveFlow);
			}
		}
		flowMap.values().forEach(p -> p.setLeaveDayStr(StringUtils.join(p.getLeaveDay(), ",")));
		return Lists.newArrayList(flowMap.values());
	}

	/**
	 * 获取某个时间段内先关员工的请假状况
	 *
	 * @author ytche
	 * @return
	 * @date 2017年8月3日 上午11:04:58
	 */
	private List<EmployeeLeaveFlow> findCusomerInLeave(Map<String, String> filter) {
		String staffIds = filter.get("staffIds");
		if (StringUtils.isBlank(staffIds)) {
			return null;
		}
		List<Long> staffIdList = Lists.newArrayList();
		for (String staffId : staffIds.split(",")) {
			staffIdList.add(new Long(staffId));
		}

		String startTimeStr = filter.get("startTime");
		String endTimeStr = filter.get("endTime");
		Integer startTime = null;
		Integer endTime = null;
		String queryHql = "from EmployeeLeaveFlow as e where e.delStatus=0 and (e.flowStatus=1 or  e.flowStatus=99) and e.applicant.id "
				+ " in(:staffIds)";
		if (StringUtils.isNotBlank(startTimeStr)) {
			startTime = new Integer(startTimeStr);
			queryHql += " and (realEndTime >= :startTime or realEndTime is null ) ";
		}
		if (StringUtils.isNotBlank(endTimeStr)) {
			endTime = new Integer(endTimeStr);
			queryHql += " and expectStartTime <= :endTime ";
		}
		Query query = super.em.createQuery(queryHql).setParameter("staffIds", staffIdList);
		if (StringUtils.isNotBlank(startTimeStr)) {
			query.setParameter("startTime", startTime);
		}
		if (StringUtils.isNotBlank(endTimeStr)) {
			query.setParameter("endTime", endTime);
		}
		return query.getResultList();
	}

	@Override
	public Integer trimEmployeeLeaveFlow(EmployeeLeaveFlow employeeLeaveFlow) {
		// 1.已销假,在当前月之前销假：请假天数=0
		// 2.已销假，在当前月销假：
		// （1）请假日期在当前月：请假天数=销假时间-请假时间+1
		// （2）请假在当前月之前：请假天数=销假时间-月初+1
		// 3.未销假
		// （1）请假日期在当前月：请假天数=月末-请假时间+1
		// （2）请假在当前月之前：请假天数=月末-月初+1
		// 销假
		Integer realEndTime = employeeLeaveFlow.getRealEndTime();// 销假时间
		Integer expectStartTime = employeeLeaveFlow.getExpectStartTime();// 实际请假时间
		/*
		 * if (null != realEndTime && CommonUtil.beforeMonthTime(realEndTime)) {
		 * return 0; } else if (null != realEndTime &&
		 * CommonUtil.integerTimeInMonth(realEndTime)) { if
		 * (CommonUtil.integerTimeInMonth(expectStartTime)) { return
		 * CommonUtil.subtractionDay(realEndTime, expectStartTime) + 1; } else {
		 * return CommonUtil.getMonthDay(realEndTime); } } else
		 */
		if (null == realEndTime) {// 未销假
			Integer preMonthLastDay = 0;
			try {
				preMonthLastDay = CommonUtil.strToIntegerTime(CommonUtil
						.getPreMonthLastDayForString());
			} catch (ParseException e) {
				logger.debug("create bill error :" + e);
				e.printStackTrace();
			}
			if (CommonUtil.integerTimeInMonth(expectStartTime)) {
				return CommonUtil.subtractionDay(preMonthLastDay, expectStartTime) + 1;
			} else {
				return CommonUtil.getMonthDay(preMonthLastDay);
			}
		} else if (CommonUtil.beforeMonthTime(realEndTime)) {// 当前月之前销假
			return 0;
		} else if (CommonUtil.integerTimeInMonth(realEndTime)) {// 当前月销假
			if (CommonUtil.integerTimeInMonth(expectStartTime)) {
				return CommonUtil.subtractionDay(realEndTime, expectStartTime) + 1;
			} else {
				return CommonUtil.getMonthDay(realEndTime);
			}
		} else {// 当前月份之后销假
			Integer preMonthLastDay = 0;
			try {
				preMonthLastDay = CommonUtil.strToIntegerTime(CommonUtil
						.getPreMonthLastDayForString());
			} catch (ParseException e) {
				logger.debug("create bill error :" + e);
				e.printStackTrace();
			}
			if (CommonUtil.integerTimeInMonth(expectStartTime)) {
				return CommonUtil.subtractionDay(preMonthLastDay, expectStartTime) + 1;
			} else {
				return CommonUtil.getMonthDay(preMonthLastDay);
			}
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<EmployeeLeaveFlow> getNotSalaryEmployeeLeaveFlow(List<Employee> employees) {
		List<Long> employIds = employeeService.sqlInParam(employees);
		StringBuilder elfSql = new StringBuilder(
				"SELECT elf from EmployeeLeaveFlow elf where elf.applicant.id in (:ids) and elf.withSalaryFlag=?2 and elf.delStatus=?3 and elf.flowStatus in(:status)");
		return this.em.createQuery(elfSql.toString()).setParameter("ids", employIds)
				.setParameter(2, 0).setParameter(3, (short) 0)
				.setParameter("status", Arrays.asList(1, 99)).getResultList();
	}

	@Override
	public Integer trimEmployeeLeaveFlow(Employee employee,
			List<EmployeeLeaveFlow> employeeLeaveFlows) {
		int leaveDays = 0;
		for (EmployeeLeaveFlow employeeLeaveFlow : employeeLeaveFlows) {
			if (employee.getId() == employeeLeaveFlow.getApplicant().getId()) {
				leaveDays = leaveDays + this.trimEmployeeLeaveFlow(employeeLeaveFlow);
			}
		}
		return leaveDays;
	}
}
